package main;

import java.awt.Button;
import java.awt.Choice;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import unit.BlackDart;

public class Hero extends Unit {
	
	protected boolean terrifyingAura = false;
	protected boolean auraOfCommand = false;
	protected boolean hasFury = false;
	protected boolean hasBlindingLight = false;
	
	
	public boolean givesStandFast(Unit ally) {
		if (this.passedBrokenTest && Utils.inchDist(this, ally) <= 6 && !(ally instanceof Hero))
			return true;
		else 
			return false;
	}
	public boolean givesCouragePass(Unit unit) {
		if ( this.armyIndex == unit.armyIndex &&
				((this.auraOfCommand == true && this.getWill() > 0 && Utils.inchDist(this, unit) <= 6)
				|| (this.hasFury && Utils.inchDist(this, unit) <= 6 && this.race == unit.race)) )
			return true;
		else
			return false;
	}
	
	public void refresh(){
		if (!layingDown)
			this.moveLeft = this.move;
		else
			this.moveLeft = 1;
		this.hasShot = false;
		this.hasFought = false;
		this.passedChargeTest = false;
		this.passedBrokenTest = false;
		this.tempTerrifying = isTerrifying;
		this.isTransfixed = false;
		this.hasUsedMagic = false;
		this.supporting = null;
		this.supporters = new ArrayList<Unit>();
		this.hasRetreated = true;
		if (this.willLeft == 0) {
			this.terrifyingAura = false;
			this.auraOfCommand = false;
			this.hasBlindingLight = false;
		}		
		for (Equipment e : this.equipmentList){
			if (e.options != null)
				e.options.select(0);
		}
		for (Button refreshButton : this.refreshButtons) {
			refreshButton.dispatchEvent(new MouseEvent(refreshButton, MouseEvent.MOUSE_CLICKED, 
					System.currentTimeMillis(), 0, 10, 10, 1, false));
		}
		this.refreshButtons.clear();
	}
	
	public ArrayList<Button> getSpellButtons() {
		ArrayList<Button> spellButtons = new ArrayList<Button>();
		if (hasUsedMagic)
			return spellButtons;
		for (String spellName : this.spellList) {
			Button castSpell = new Button(spellName);
			castSpell.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					// Currently only support non-targeted, non-AOE spells
					// Also not supporting multiple will usage
					Utils.spellType type = Utils.getSpellType(spellName);
					if (type == Utils.spellType.UNTARGETED) {
						NumberSelecter willToUse = new NumberSelecter(1, willLeft, 1, "Will to use", game.myUI, null);
						Button codeToExecute = new Button();
						codeToExecute.addMouseListener(new MouseListener() {
							public void mouseClicked(MouseEvent e) {
								castSpell(spellName, willToUse.getNumber());
							}
							public void mouseEntered(MouseEvent arg0) {}
							public void mouseExited(MouseEvent arg0) {}
							public void mousePressed(MouseEvent arg0) {}
							public void mouseReleased(MouseEvent arg0) {}
						});
						willToUse.setCodeToExecute(codeToExecute);
					}
					else if (type == Utils.spellType.TARGETED) {
						game.myUI.storeVisibleComponents();
						game.myUI.disableComponents();
						UI.messageLog.add("Select target for spell");
						MoveUI myMoveUI = (MoveUI)game.myUI.phaseUI;
						myMoveUI.targetingMagic = true;
						myMoveUI.spellToCast = new Button();
						myMoveUI.spellToCast.addMouseListener(new MouseListener() {
							public void mouseClicked(MouseEvent e) {
								game.myUI.reenableComponents();
								if (myMoveUI.magicTarget != null && canSee(myMoveUI.magicTarget)) {
									NumberSelecter willToUse = new NumberSelecter(1, willLeft, 1, "Will to use", game.myUI, null);
									Button codeToExecute = new Button();
									codeToExecute.addMouseListener(new MouseListener() {
										public void mouseClicked(MouseEvent e) {
											castTargetedSpell(spellName, willToUse.getNumber(), myMoveUI.magicTarget);
										}
										public void mouseEntered(MouseEvent arg0) {}
										public void mouseExited(MouseEvent arg0) {}
										public void mousePressed(MouseEvent arg0) {}
										public void mouseReleased(MouseEvent arg0) {}
									});
									willToUse.setCodeToExecute(codeToExecute);
								}
								else if (!canSee(myMoveUI.magicTarget)) {
									UI.messageLog.add("Can't see the target!");
								}
								else{
									UI.messageLog.add("No target selected!");
								}
								game.myUI.repaint();
							}
							public void mouseEntered(MouseEvent e) {}
							public void mouseExited(MouseEvent e) {}
							public void mousePressed(MouseEvent e) {}
							public void mouseReleased(MouseEvent e) {}
						});
						game.myUI.repaint();					
					}
				}
			});
			spellButtons.add(castSpell);
		}
		return spellButtons;
	}
	
	public void castSpell(String spellName, int numDice) {
		if (!this.spellList.contains(spellName)){
			System.out.println("BUG: " + this.toChoiceString() + " trying to cast " + spellName);
			return;
		}
		switch (spellName) {
		case "Terrifying Aura":
			this.castTerrifyingAura(numDice);
			break;
		case "Aura of Dismay":
			this.castAuraOfDismay(numDice);
			break;
		case "Aura of Command":
			this.castAuraOfCommand(numDice);
			break;
		case "Blinding Light":
			this.castBlindingLight(numDice);
			break;
		case "Fury":
			this.castFury(numDice);
			break;
		case "Nature's Wrath":
			this.castNaturesWrath(numDice);
			break;
		default:
			System.out.println("Unimplemented spell cast: " + spellName);
		}
	}

	public void castTargetedSpell(String spellName, int numDice, Unit target){
		if (!this.spellList.contains(spellName)){
			System.out.println("BUG: " + this.toChoiceString() + " trying to cast " + spellName);
			return;
		}
		switch (spellName) {
		case "Black Dart":
			this.castBlackDart(numDice, target);
			break;
		case "Chill Soul":
			this.castChillSoul(numDice, target);
			break;
		case "Command":
			this.castCommand(numDice, target);
			break;
		case "Compel":
			this.castCompel(numDice, target);
			break;
		case "Drain Courage":
			this.castDrainCourage(numDice, target);
			break;
		case "Immobilize":
			this.castImmobilize(numDice, target);
			break;
		case "Transfix":
			this.castTransfix(numDice, target);
			break;
		case "Renew":
			this.castRenew(numDice, target);
			break;
		case "Sap Will":
			this.castSapWill(numDice, target);
			break;
		case "Sorcerous Blast":
			this.castSorcerousBlast(numDice, target);
			break;
		case "Strengthen Will":
			this.castStrengthenWill(numDice, target);
			break;
		default:
			System.out.println("Unimplemented spell cast: " + spellName);
		}
	}
	
	public void castAOESpell(String spellName, int numDice, int x, int y){
		if (!this.spellList.contains(spellName)){
			System.out.println("BUG: " + this.toChoiceString() + " trying to cast " + spellName);
			return;
		}
		switch (spellName) {
		default:
			System.out.println("Unimplemented spell cast: " + spellName);
		}
	}
	
	
	// Spells
	// Non-targeted
	private void castAuraOfCommand(int numDice) {
		int neededToHit = 2;
		
		if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}
		
		// If we can't use might, just get the rolls 
		if(!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Aura of Command with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				this.auraOfCommand = true;
			}
			game.myUI.reenableComponents();
			game.myUI.selectUnit(this);
			game.myUI.repaint();
		}
		// Otherwise we may want to use might to affect the rolls
		else {
			Unit thisUnit = this;
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " casts Aura of Command with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					if (maxRoll >= neededToHit) {
						auraOfCommand = true;
					}
					game.myUI.disableMight();
					game.myUI.reenableComponents();
					game.myUI.selectUnit(thisUnit);
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	private void castAuraOfDismay(int numDice) {
		// add callback to endphase adding terror to close units
		int neededToHit = 5;
		
		if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}
		
		// If we can't adjust rolls, do what's necessary
		if (!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Aura of Dismay with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				UI.messageLog.add("Successfully cast. Models ending within 6in. of " + toChoiceString() + " will be terrifying this turn");
				Unit thisUnit = this;
				ActionListener addAura = new ActionListener() {
					public void actionPerformed(ActionEvent e) {
						for (Unit ally : army.units) {
							if (Utils.inchDist(thisUnit, ally) <= 6) {
								ally.tempTerrifying = true;
							}
						}
						game.myUI.endPhase.removeActionListener(this);
					}
				};
				game.myUI.endPhase.addActionListener(addAura);
			}
			game.myUI.reenableComponents();
			game.myUI.repaint();
		}
		// Otherwise we can use might, tie it to the might button
		else {
			Unit thisUnit = this;
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e){
					UI.messageLog.add(toChoiceString() + " casts Aura of Dismay with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					game.myUI.disableMight();
					if (maxRoll >= neededToHit) {
						UI.messageLog.add("Successfully cast. Models ending within 6in. of " + toChoiceString() + " will be terrifying this turn");
						ActionListener addAura = new ActionListener() {
							public void actionPerformed(ActionEvent e) {
								for (Unit ally : army.units) {
									if (Utils.inchDist(thisUnit, ally) <= 6) {
										ally.tempTerrifying = true;
									}
								}
								game.myUI.endPhase.removeActionListener(this);
							}
						};
						game.myUI.endPhase.addActionListener(addAura);
					}
					game.myUI.reenableComponents();
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	private void castBlindingLight(int numDice) {
		int neededToHit = 2;
		
		if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}
		
		// If we can't use might, just get the rolls 
		if(!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Blinding Light with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				this.hasBlindingLight = true;
			}
			game.myUI.reenableComponents();
			game.myUI.selectUnit(this);
			game.myUI.repaint();
		}
		// Otherwise we may want to use might to affect the rolls
		else {
			Unit thisUnit = this;
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " casts Blinding Light with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					if (maxRoll >= neededToHit) {
						hasBlindingLight = true;
					}
					game.myUI.disableMight();
					game.myUI.reenableComponents();
					game.myUI.selectUnit(thisUnit);
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	private void castTerrifyingAura(int numDice) {
		int neededToHit = 2;
		
		if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}
		
		// If we can't use might, just get the rolls 
		if(!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Terrifying Aura with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				this.terrifyingAura = true;
			}
			game.myUI.reenableComponents();
			game.myUI.selectUnit(this);
			game.myUI.repaint();
		}
		// Otherwise we may want to use might to affect the rolls
		else {
			Unit thisUnit = this;
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " casts Terrifying Aura with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					if (maxRoll >= neededToHit) {
						terrifyingAura = true;
					}
					game.myUI.disableMight();
					game.myUI.reenableComponents();
					game.myUI.selectUnit(thisUnit);
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}

	private void castFury(int numDice) {
		int neededToHit = 3;
		
		if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}
		
		// If we can't use might, just get the rolls 
		if(!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Fury with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				this.hasFury = true;
			}
			game.myUI.reenableComponents();
			game.myUI.selectUnit(this);
			game.myUI.repaint();
		}
		// Otherwise we may want to use might to affect the rolls
		else {
			Unit thisUnit = this;
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " casts Fury with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					if (maxRoll >= neededToHit) {
						hasFury = true;
					}
					game.myUI.disableMight();
					game.myUI.reenableComponents();
					game.myUI.selectUnit(thisUnit);
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}

	private void castNaturesWrath(int numDice) {
		int neededToHit = 4;
		
		if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}

		Unit thisUnit = this;
		
		// If we can't use might, just get the rolls 
		if(!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Nature's Wrath with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				final int finalMaxRoll = maxRoll;
				
				ArrayList<Unit> resisters = new ArrayList<Unit>();
				Choice resisterChoice = new Choice();
				resisterChoice.setBounds(game.myUI.dim.width-200, 10, 100, 20);
				resisterChoice.add("None");
				for (Unit u : game.armies[(this.armyIndex+1)%2].units){
					if (u.canResist() && Utils.inchDist(thisUnit, u) <= 6) {
						resisterChoice.add(u.toChoiceString());
						resisters.add(u);
					}
				}
				
				// No one able to resist
				if (resisters.size() == 0) {
					game.myUI.reenableComponents();
					for (Army a : game.armies){
						for (Unit u : a.units){
							if (Utils.inchDist(u, thisUnit) <= 6 && u.id != thisUnit.id)
								u.knockDown();
						}
					}
					game.myUI.selectUnit(thisUnit);
				}
				// May be some resisters
				else {
					game.myUI.add(resisterChoice);
					
					Button doneSelecting = new Button("Choose");
					doneSelecting.setBounds(game.myUI.dim.width-100, 0, 100, 50);
					doneSelecting.addActionListener(new ActionListener() {
						public void actionPerformed(ActionEvent e) {
							game.myUI.remove(resisterChoice);
							game.myUI.remove(doneSelecting);
							
							Unit target = Utils.getFromListByString(resisters, resisterChoice.getSelectedItem());
							if (target == null) {
								// No resister
								game.myUI.reenableComponents();
								for (Army a : game.armies){
									for (Unit u : a.units){
										if (Utils.inchDist(u, thisUnit) <= 6 && u.id != thisUnit.id)
											u.knockDown();
									}
								}
								game.myUI.selectUnit(thisUnit);
							}
							else {
								Button resistFail = new Button();
								resistFail.addMouseListener(new MouseListener() {
									public void mouseClicked(MouseEvent e) {
										game.myUI.reenableComponents();
										for (Army a : game.armies){
											for (Unit u : a.units){
												if (Utils.inchDist(u, thisUnit) <= 6 && u.id != thisUnit.id)
													u.knockDown();
											}
										}
										game.myUI.selectUnit(thisUnit);
										game.myUI.repaint();
									}
									public void mouseEntered(MouseEvent e) {}
									public void mouseExited(MouseEvent e) {}
									public void mousePressed(MouseEvent e) {}
									public void mouseReleased(MouseEvent e) {}
								});
								
								Button resistSucceed = new Button();
								resistSucceed.addMouseListener(new MouseListener() {
									public void mouseClicked(MouseEvent e) {
										UI.messageLog.add("Resist succeeded!");
										game.myUI.reenableComponents();
										game.myUI.selectUnit(thisUnit);
										game.myUI.repaint();
									}
									public void mouseEntered(MouseEvent e) {}
									public void mouseExited(MouseEvent e) {}
									public void mousePressed(MouseEvent e) {}
									public void mouseReleased(MouseEvent e) {}
								});
								
								target.resistMagic(finalMaxRoll, resistSucceed, resistFail);
							}
						}
					});
					game.myUI.add(doneSelecting);
					UI.messageLog.add("Choose a unit to resist Nature's Wrath");
				}
			}
			else {
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
			}
			game.myUI.repaint();
		}
		// Otherwise, we can use might
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " casts Nature's Wrath with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					game.myUI.disableMight();
					if (maxRoll >= neededToHit) {
						final int finalMaxRoll = maxRoll;
						
						ArrayList<Unit> resisters = new ArrayList<Unit>();
						Choice resisterChoice = new Choice();
						resisterChoice.setBounds(game.myUI.dim.width-200, 10, 100, 20);
						resisterChoice.add("None");
						for (Unit u : game.armies[(armyIndex+1)%2].units){
							if (u.canResist() && Utils.inchDist(thisUnit, u) <= 6) {
								resisterChoice.add(u.toChoiceString());
								resisters.add(u);
							}
						}
						
						// No one able to resist
						if (resisters.size() == 0) {
							game.myUI.reenableComponents();
							for (Army a : game.armies){
								for (Unit u : a.units){
									if (Utils.inchDist(u, thisUnit) <= 6 && u.id != thisUnit.id)
										u.knockDown();
								}
							}
						}
						// May be some resisters
						else {
							game.myUI.add(resisterChoice);
							
							Button doneSelecting = new Button("Choose");
							doneSelecting.setBounds(game.myUI.dim.width-100, 0, 100, 50);
							doneSelecting.addActionListener(new ActionListener() {
								public void actionPerformed(ActionEvent e) {
									game.myUI.remove(resisterChoice);
									game.myUI.remove(doneSelecting);
									
									Unit target = Utils.getFromListByString(resisters, resisterChoice.getSelectedItem());
									if (target == null) {
										// No resister
										game.myUI.reenableComponents();
										for (Army a : game.armies){
											for (Unit u : a.units){
												if (Utils.inchDist(u, thisUnit) <= 6 && u.id != thisUnit.id)
													u.knockDown();
											}
										}
										game.myUI.selectUnit(thisUnit);
									}
									else {
										Button resistFail = new Button();
										resistFail.addMouseListener(new MouseListener() {
											public void mouseClicked(MouseEvent e) {
												game.myUI.reenableComponents();
												for (Army a : game.armies){
													for (Unit u : a.units){
														if (Utils.inchDist(u, thisUnit) <= 6 && u.id != thisUnit.id)
															u.knockDown();
													}
												}
												game.myUI.selectUnit(thisUnit);
												game.myUI.repaint();
											}
											public void mouseEntered(MouseEvent e) {}
											public void mouseExited(MouseEvent e) {}
											public void mousePressed(MouseEvent e) {}
											public void mouseReleased(MouseEvent e) {}
										});
										
										Button resistSucceed = new Button();
										resistSucceed.addMouseListener(new MouseListener() {
											public void mouseClicked(MouseEvent e) {
												UI.messageLog.add("Resist succeeded!");
												game.myUI.reenableComponents();
												game.myUI.selectUnit(thisUnit);
												game.myUI.repaint();
											}
											public void mouseEntered(MouseEvent e) {}
											public void mouseExited(MouseEvent e) {}
											public void mousePressed(MouseEvent e) {}
											public void mouseReleased(MouseEvent e) {}
										});
										
										target.resistMagic(finalMaxRoll, resistSucceed, resistFail);
									}
									game.myUI.repaint();
								}
							});
							game.myUI.add(doneSelecting);
						}
					}
					else {
						game.myUI.reenableComponents();
						game.myUI.selectUnit(thisUnit);
					}
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	// Targeted
	private void castBlackDart(int numDice, Unit target) {
		int neededToHit = 5;
		int range = 12;
		
		if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		else if (Utils.inchDist(this, target) > range) {
			UI.messageLog.add("Too far away, range is "+range);
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}
		
		Unit thisUnit = this;
		
		Button resistFail = new Button();
		resistFail.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
				Button doneStriking = new Button();
				doneStriking.addMouseListener(new MouseListener() {
					public void mouseClicked(MouseEvent arg0) {
						game.myUI.reenableComponents();
						game.myUI.selectUnit(thisUnit);
						if(target.getWounds() <= 0)
							game.myUI.targetedUnit = null;
						game.myUI.repaint();
					}
					public void mouseEntered(MouseEvent arg0) {}
					public void mouseExited(MouseEvent arg0) {}
					public void mousePressed(MouseEvent arg0) {}
					public void mouseReleased(MouseEvent arg0) {}
				});
				Unit dart = new BlackDart(game);
				dart.strike(target, doneStriking);
				if(target.getWounds() <= 0)
					game.myUI.targetedUnit = null;
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});
		
		Button resistSucceed = new Button();
		resistSucceed.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				UI.messageLog.add("Resist succeeded!");
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});
		
		
		// If we can't use might, just get the rolls 
		if(!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Black Dart with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				target.resistMagic(maxRoll, resistSucceed, resistFail);
			}
			else {
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
			}
			game.myUI.repaint();
		}
		// Otherwise we may want to use might to affect the rolls
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " casts Black Dart with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					game.myUI.disableMight();
					if (maxRoll >= neededToHit) {
						target.resistMagic(maxRoll, resistSucceed, resistFail);
					}
					else{
						game.myUI.reenableComponents();
						game.myUI.selectUnit(thisUnit);
					}
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}

	private void castChillSoul(int numDice, Unit target) {
		int neededToHit = 4;
		int range = 18;
		
		if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		else if (Utils.inchDist(this, target) > range) {
			UI.messageLog.add("Too far away, range is " + range);
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}
		

		Unit thisUnit = this;
		
		Button resistFail = new Button();
		resistFail.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
				Button doneStriking = new Button();
				doneStriking.addMouseListener(new MouseListener() {
					public void mouseClicked(MouseEvent arg0) {
						game.myUI.reenableComponents();
						game.myUI.selectUnit(thisUnit);
						if(target.getWounds() <= 0)
							game.myUI.targetedUnit = null;
						game.myUI.repaint();
					}
					public void mouseEntered(MouseEvent arg0) {}
					public void mouseExited(MouseEvent arg0) {}
					public void mousePressed(MouseEvent arg0) {}
					public void mouseReleased(MouseEvent arg0) {}
				});
				target.takeStrike(10, 7, doneStriking);
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});
		
		Button resistSucceed = new Button();
		resistSucceed.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				UI.messageLog.add("Resist succeeded!");
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});

		
		// If we can't use might, just get the rolls 
		if(!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Chill Soul with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				target.resistMagic(maxRoll, resistSucceed, resistFail);
			}
			else {
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
			}
			game.myUI.repaint();
		}
		// Otherwise we may want to use might to affect the rolls
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " casts Chill Soul with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					game.myUI.disableMight();
					if (maxRoll >= neededToHit) {
						target.resistMagic(maxRoll, resistSucceed, resistFail);
					}
					else{
						game.myUI.reenableComponents();
						game.myUI.selectUnit(thisUnit);
					}
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}

	private void castDrainCourage(int numDice, Unit target) {
		int neededToHit = 2;
		int range = 12;
		
		if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		else if (Utils.inchDist(this, target) > range) {
			UI.messageLog.add("Too far away, range is " + range);
			game.myUI.repaint();
			return;
		}
		else if (target.getCourage() <= 0) {
			UI.messageLog.add("Target already has 0 courage");
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}

		Unit thisUnit = this;
		
		Button resistFail = new Button();
		resistFail.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
				target.setCourage(target.getCourage() - 1);
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});
		
		Button resistSucceed = new Button();
		resistSucceed.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				UI.messageLog.add("Resist succeeded!");
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});
		
		// If we can't use might, just get the rolls 
		if(!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Drain Courage with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				target.resistMagic(maxRoll, resistSucceed, resistFail);
			}
			else {
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
			}
			game.myUI.repaint();
		}
		// Otherwise we may want to use might to affect the rolls
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " casts Drain Courage with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					game.myUI.disableMight();
					if (maxRoll >= neededToHit) {
						target.resistMagic(maxRoll, resistSucceed, resistFail);
					}
					else{
						game.myUI.reenableComponents();
						game.myUI.selectUnit(thisUnit);
					}
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}

	private void castCommand(int numDice, Unit target) {
		int neededToHit = 4;
		int range = 12;
		
		if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		else if (target.armyIndex == this.armyIndex){
			UI.messageLog.add("Cannot cast Command on friendly unit");
			game.myUI.repaint();
			return;
		}
		else if (Utils.inchDist(this, target) > range) {
			UI.messageLog.add("Too far away, range is " + range);
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}

		Unit thisUnit = this;
		
		Button resistFail = new Button();
		resistFail.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				

				Button doneMoving = new Button("Done Commanding");
				doneMoving.setBounds(game.myUI.dim.width-100, game.myUI.dim.height - 330, 100, 50);
				doneMoving.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent e){
						game.myUI.remove(doneMoving);
						game.myUI.reenableComponents();
					
						// unset compelling, reset selectUnit
						((MoveUI)game.myUI.phaseUI).compelMoving = false;
						game.myUI.selectedUnit.moveLeft = 0;
						target.isTransfixed = true;
						game.myUI.selectUnit(thisUnit);
						game.myUI.repaint();
					}
				});
				game.myUI.add(doneMoving);
				
				((MoveUI)game.myUI.phaseUI).compelMoving = true;
				target.moveLeft = target.move/2;
				game.myUI.selectUnit(target);
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});
		
		Button resistSucceed = new Button();
		resistSucceed.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				UI.messageLog.add("Resist succeeded!");
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});
		
		// If we can't use might, just get the rolls 
		if(!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Command with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				target.resistMagic(maxRoll, resistSucceed, resistFail);
			}
			else {
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
			}
			game.myUI.repaint();
		}
		// Otherwise we may want to use might to affect the rolls
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " casts Command with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					game.myUI.disableMight();
					if (maxRoll >= neededToHit) {
						target.resistMagic(maxRoll, resistSucceed, resistFail);
					}
					else{
						game.myUI.reenableComponents();
						game.myUI.selectUnit(thisUnit);
					}
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	private void castCompel(int numDice, Unit target) {
		int neededToHit = 4;
		int range = 12;
		
		if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		else if (target.armyIndex == this.armyIndex){
			UI.messageLog.add("Cannot cast Compel on friendly unit");
			game.myUI.repaint();
			return;
		}
		else if (Utils.inchDist(this, target) > range) {
			UI.messageLog.add("Too far away, range is " + range);
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}

		Unit thisUnit = this;
		
		Button resistFail = new Button();
		resistFail.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				

				Button doneMoving = new Button("Done Compelling");
				doneMoving.setBounds(game.myUI.dim.width-100, game.myUI.dim.height - 330, 100, 50);
				doneMoving.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent e){
						game.myUI.remove(doneMoving);
						game.myUI.reenableComponents();
					
						// unset compelling, reset selectUnit
						((MoveUI)game.myUI.phaseUI).compelMoving = false;
						game.myUI.selectedUnit.moveLeft = 0;
						target.isTransfixed = true;
						game.myUI.selectUnit(thisUnit);
						game.myUI.repaint();
					}
				});
				game.myUI.add(doneMoving);
				
				((MoveUI)game.myUI.phaseUI).compelMoving = true;
				target.moveLeft = target.move/2;
				game.myUI.selectUnit(target);
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});
		
		Button resistSucceed = new Button();
		resistSucceed.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				UI.messageLog.add("Resist succeeded!");
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});
		
		// If we can't use might, just get the rolls 
		if(!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Compel with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				target.resistMagic(maxRoll, resistSucceed, resistFail);
			}
			else {
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
			}
			game.myUI.repaint();
		}
		// Otherwise we may want to use might to affect the rolls
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " casts Compel with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					game.myUI.disableMight();
					if (maxRoll >= neededToHit) {
						target.resistMagic(maxRoll, resistSucceed, resistFail);
					}
					else{
						game.myUI.reenableComponents();
						game.myUI.selectUnit(thisUnit);
					}
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	private void castImmobilize(int numDice, Unit target) {
		int neededToHit = 3;
		int range = 12;
		
		if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		else if (Utils.inchDist(this, target) > range) {
			UI.messageLog.add("Too far away, range is " + range);
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}

		Unit thisUnit = this;
		
		Button resistFail = new Button();
		resistFail.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				game.myUI.reenableComponents();
				target.moveLeft = 0;
				target.isTransfixed = true;
				game.myUI.selectUnit(thisUnit);
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});
		
		Button resistSucceed = new Button();
		resistSucceed.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				UI.messageLog.add("Resist succeeded!");
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});
		
		// If we can't use might, just get the rolls 
		if(!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Immobilize with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				target.resistMagic(maxRoll, resistSucceed, resistFail);
			}
			else {
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
			}
			game.myUI.repaint();
		}
		// Otherwise we may want to use might to affect the rolls
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " casts Immobilize with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					game.myUI.disableMight();
					if (maxRoll >= neededToHit) {
						target.resistMagic(maxRoll, resistSucceed, resistFail);
					}
					else{
						game.myUI.reenableComponents();
						game.myUI.selectUnit(thisUnit);
					}
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	private void castTransfix(int numDice, Unit target) {
		int neededToHit = 5;
		int range = 12;
		
		if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		else if (Utils.inchDist(this, target) > range) {
			UI.messageLog.add("Too far away, range is " + range);
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}

		Unit thisUnit = this;
		
		Button resistFail = new Button();
		resistFail.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				game.myUI.reenableComponents();
				target.moveLeft = 0;
				target.isTransfixed = true;
				game.myUI.selectUnit(thisUnit);
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});
		
		Button resistSucceed = new Button();
		resistSucceed.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				UI.messageLog.add("Resist succeeded!");
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});
		
		// If we can't use might, just get the rolls 
		if(!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Transfix with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				target.resistMagic(maxRoll, resistSucceed, resistFail);
			}
			else {
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
			}
			game.myUI.repaint();
		}
		// Otherwise we may want to use might to affect the rolls
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " casts Transfix with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					game.myUI.disableMight();
					if (maxRoll >= neededToHit) {
						target.resistMagic(maxRoll, resistSucceed, resistFail);
					}
					else{
						game.myUI.reenableComponents();
						game.myUI.selectUnit(thisUnit);
					}
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	private void castRenew(int numDice, Unit target) {
		int neededToHit = 3;
		int range = 12;
		
		if (this.armyIndex != target.armyIndex) {
			UI.messageLog.add("Must cast Renew on friendly unit");
			game.myUI.repaint();
			return;
		}
		else if (target.getWounds() >= target.wounds) {
			UI.messageLog.add("Already at full health");
			game.myUI.repaint();
			return;
		}
		else if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		else if (Utils.inchDist(this, target) > range) {
			UI.messageLog.add("Too far away, range is " + range);
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}

		Unit thisUnit = this;
		
		// If we can't use might, just get the rolls 
		if(!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Renew with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				target.healWound(1);
			}
			game.myUI.reenableComponents();
			game.myUI.selectUnit(thisUnit);
			game.myUI.repaint();
		}
		// Otherwise we may want to use might to affect the rolls
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " casts Renew with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					game.myUI.disableMight();
					if (maxRoll >= neededToHit) {
						target.healWound(1);
					}
					game.myUI.reenableComponents();
					game.myUI.selectUnit(thisUnit);
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	private void castSapWill(int numDice, Unit target) {
		int neededToHit = 3;
		int range = 12;
		
		if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		else if (Utils.inchDist(this, target) > range) {
			UI.messageLog.add("Too far away, range is " + range);
			game.myUI.repaint();
			return;
		}
		else if (target.getWill() <= 0) {
			UI.messageLog.add("Target already has 0 will");
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}

		Unit thisUnit = this;
		
		Button resistFail = new Button();
		resistFail.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
				target.willLeft = 0;
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});
		
		Button resistSucceed = new Button();
		resistSucceed.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				UI.messageLog.add("Resist succeeded!");
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});
		
		// If we can't use might, just get the rolls 
		if(!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Sap Will with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				target.resistMagic(maxRoll, resistSucceed, resistFail);
			}
			else {
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
			}
			game.myUI.repaint();
		}
		// Otherwise we may want to use might to affect the rolls
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " casts Sap Will with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					game.myUI.disableMight();
					if (maxRoll >= neededToHit) {
						target.resistMagic(maxRoll, resistSucceed, resistFail);
					}
					else{
						game.myUI.reenableComponents();
						game.myUI.selectUnit(thisUnit);
					}
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	private void castSorcerousBlast(int numDice, Unit target) {
		int neededToHit = 5;
		int range = 12;
		
		if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		else if (Utils.inchDist(this, target) > range) {
			UI.messageLog.add("Too far away, range is " + range);
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}
		

		Unit thisUnit = this;
		
		Button resistFail = new Button();
		resistFail.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
				
				// Need to get path of struck unit, find units that are knocked to ground
				
				// Get distance to travel
				double inchesToTravel = UI.rng.nextInt(6) + 1; // Distance the unit is blasted (not modifiable)
				double distToTravel = inchesToTravel * Utils.pixelsPerInch;
				UI.messageLog.add(target.toChoiceString() + " is blasted " + (int)inchesToTravel + " inches");
				double theta = Math.atan2(thisUnit.y-target.y, thisUnit.x-target.x);
				int destX = target.x - (int) (distToTravel * Math.cos(theta));
				int destY = target.y - (int) (distToTravel * Math.sin(theta));
				
				
				// find all units + x,y intersects, check for furthest x,y
				ArrayList<Unit> knockedUnits = new ArrayList<Unit>();
				for (Army a : game.armies) {
					for (Unit u : a.units) {
						Point2D contactPoint = Utils.findContactPoint(target, u, destX, destY);
						if (contactPoint != null) {
							knockedUnits.add(u);
						}
					}
				}
				class CustomComp implements Comparator<Unit>{
					public Unit mover;
					public CustomComp(Unit mover) {
						this.mover = mover;
					}
					public int compare(Unit u1, Unit u2) {
						Point2D u1Point = Utils.findContactPoint(mover, u1, destX, destY);
						Point2D u2Point = Utils.findContactPoint(mover, u2, destX, destY);
						return (int)Math.round(Utils.pixelDist(u1Point.getX(), u1Point.getY(), mover.x, mover.y) -
								Utils.pixelDist(u2Point.getX(), u2Point.getY(), mover.x, mover.y));
					}
				}
				CustomComp myTComp = new CustomComp(target);
				Collections.sort(knockedUnits, myTComp);
				
				
				// Find furthest collision point that we can place the unit on, and truncate the list if we
				// run into a >6 strength unit, as per the rules
				Point2D finalPt = null;
				for (int i = 0; i < knockedUnits.size(); i++) {
					Unit gettingKnocked = knockedUnits.get(i);
					Point2D collidePt = Utils.findContactPoint(target, gettingKnocked, destX, destY);
					if (game.canPlace(target, (int)collidePt.getX(), (int)collidePt.getY())) {
						finalPt = collidePt;
					}
					if (target.getStrength() < 6 && gettingKnocked.getStrength() >= 6) {
						while (knockedUnits.size() > i+1)
							knockedUnits.remove(i+1);
						break;
					}
				}
				
				// go through units removing battles and adding battle participants if necessary.
				if (target.battle != null) {
					game.battles.remove(target.battle);
					for (Unit u : target.battle.getAllUnits()) {
						u.battle = null;
						if (!knockedUnits.contains(u))
							knockedUnits.add(0,u);
					}
				}
				int i = 0;
				while (i < knockedUnits.size()) {
					Unit u = knockedUnits.get(i);
					if (u.battle != null) {
						game.battles.remove(u.battle);
						for (Unit fighter : target.battle.getAllUnits()) {
							fighter.battle = null;
							if (!knockedUnits.contains(fighter)) {
								knockedUnits.add(i,u);
								i += 1;
							}
						}
					}
					i += 1;
				}
				
				if (knockedUnits.contains(target))
					knockedUnits.remove(target);
				
				// go through units striking each of them (will need to set up doneStriking to do another strike
				// Will need to check all units for strength differential when knocking down, since could have been
				// added from a battle.
				class CustomMouseListener implements MouseListener {
					ArrayList<Unit> knockedUnits;
					int knockingIndex;
					Button myButton;
					
					public void mouseClicked(MouseEvent e) {
						knockingIndex += 1;
						if (knockingIndex >= knockedUnits.size()) {
							game.myUI.reenableComponents();
							game.myUI.selectUnit(thisUnit);
							game.myUI.repaint();
						}
						else {
							Unit unitToKnock = knockedUnits.get(knockingIndex);
							if (!(target.strength < 6 && unitToKnock.strength >= 6))
								unitToKnock.knockDown();
							int knockDownWoundRoll = Game.rng.nextInt(6) + 1;
							UI.messageLog.add(unitToKnock.toChoiceString() + " is taking a strength 3 hit with a roll of " + knockDownWoundRoll);
							target.takeStrike(3, knockDownWoundRoll, myButton);
							game.myUI.repaint();
						}
					}
					public void mouseEntered(MouseEvent e) {}
					public void mouseExited(MouseEvent e) {}
					public void mousePressed(MouseEvent e) {}
					public void mouseReleased(MouseEvent e) {}
				}
				
				Button doneStriking = new Button();
				CustomMouseListener chainStrikeListener = new CustomMouseListener();
				chainStrikeListener.knockedUnits = knockedUnits;
				chainStrikeListener.knockingIndex = -1;
				chainStrikeListener.myButton = doneStriking;
				doneStriking.addMouseListener(chainStrikeListener);
				
				if (game.canPlace(target, destX, destY)) {
					target.x = destX;
					target.y = destY;
				}
				else if (finalPt != null) {
					target.x = (int)finalPt.getX();
					target.y = (int)finalPt.getY();
				}
				target.knockDown();
				int targetWoundRoll = Game.rng.nextInt(6) + 1;
				UI.messageLog.add("Target is taking a strength 5 hit with a roll of " + targetWoundRoll);
				target.takeStrike(5, targetWoundRoll, doneStriking);
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});
		
		Button resistSucceed = new Button();
		resistSucceed.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				UI.messageLog.add("Resist succeeded!");
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
				game.myUI.repaint();
			}
			public void mouseEntered(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mousePressed(MouseEvent e) {}
			public void mouseReleased(MouseEvent e) {}
		});

		
		// If we can't use might, just get the rolls 
		if(!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Sorcerous Blast with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				target.resistMagic(maxRoll, resistSucceed, resistFail);
			}
			else {
				game.myUI.reenableComponents();
				game.myUI.selectUnit(thisUnit);
			}
			game.myUI.repaint();
		}
		// Otherwise we may want to use might to affect the rolls
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " casts Sorcerous Blast with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					game.myUI.disableMight();
					if (maxRoll >= neededToHit) {
						target.resistMagic(maxRoll, resistSucceed, resistFail);
					}
					else{
						game.myUI.reenableComponents();
						game.myUI.selectUnit(thisUnit);
					}
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	private void castStrengthenWill(int numDice, Unit target) {
		int neededToHit = 4;
		int range = 12;
		
		if (this.armyIndex != target.armyIndex || !(target instanceof Hero)) {
			UI.messageLog.add("Must cast Strengthen Will on friendly hero");
			game.myUI.repaint();
			return;
		}
		else if (target.getWill() >= target.will && target.will > 0) {
			UI.messageLog.add("Already at full Will");
			game.myUI.repaint();
			return;
		}
		else if (this.getWill() < numDice){
			UI.messageLog.add("Not enough will to cast");
			game.myUI.repaint();
			return;
		}
		else if (Utils.inchDist(this, target) > range) {
			UI.messageLog.add("Too far away, range is " + range);
			game.myUI.repaint();
			return;
		}
		this.useWill(numDice);
		hasUsedMagic = true;
		
		
		ArrayList<DieRoll> castRolls = new ArrayList<DieRoll>();
		game.myUI.storeVisibleComponents();
		game.myUI.disableComponents();
		
		boolean canUseMight = false;
		for(int i = 0; i < numDice; i++){
			DieRoll castRoll = new DieRoll(this, game.myUI.dim.width-200, game.myUI.dim.height/2-30*(i+1), 
											neededToHit+"+ to cast", game.myUI);
			castRolls.add(castRoll);
			if(castRoll.isModifiable())
				canUseMight = true;
		}

		Unit thisUnit = this;
		
		// If we can't use might, just get the rolls 
		if(!canUseMight) {
			UI.messageLog.add(this.toChoiceString() + " casts Strengthen Will with rolls of " + castRolls.toString());
			int maxRoll = 0;
			for (DieRoll dr : castRolls) {
				if (dr.getRoll() > maxRoll)
					maxRoll = dr.getRoll();
				dr.cleanup();
			}
			if (maxRoll >= neededToHit) {
				target.willLeft += 1;
			}
			game.myUI.reenableComponents();
			game.myUI.selectUnit(thisUnit);
			game.myUI.repaint();
		}
		// Otherwise we may want to use might to affect the rolls
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add(toChoiceString() + " casts Strengthen Will with rolls of " + castRolls.toString());
					int maxRoll = 0;
					for (DieRoll dr : castRolls) {
						if (dr.getRoll() > maxRoll)
							maxRoll = dr.getRoll();
						dr.cleanup();
					}
					game.myUI.disableMight();
					if (maxRoll >= neededToHit) {
						target.willLeft += 1;
					}
					game.myUI.reenableComponents();
					game.myUI.selectUnit(thisUnit);
					game.myUI.repaint();
				}
			};
			game.myUI.enableMight(mightDone);
		}
	}
	
	
	
	public boolean isTerrifying() {
		return (this.tempTerrifying || (this.terrifyingAura && this.getWill() > 0));
	}
	
}
